﻿#include "ThreePointCircleGraphicsItem.h"
#include "GraphicsDef.h"
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QPainter>
#include <QFocusEvent>

namespace OfUI {

	ThreePointCircleGraphicsItem::ThreePointCircleGraphicsItem(QGraphicsItem *parent)
		: BaseGraphicsItem(parent)
		, m_vCirclePoint(3)
		, m_bAdding(true)
		, m_eSelType(SELECT_NONE)
	{
		setType(ItemType::THREE_POINT_CIRCLE);
	}

	ThreePointCircleGraphicsItem::~ThreePointCircleGraphicsItem()
	{
	}

	void ThreePointCircleGraphicsItem::setCirclePoint(const QVector<QPointF>& vPoints)
	{
		prepareGeometryChange();
		m_vCirclePoint = vPoints;
		emit signalDataChanged();
	}

	QVector<QPointF> ThreePointCircleGraphicsItem::getCirclePoint() const
	{
		return m_vCirclePoint;
	}

	bool ThreePointCircleGraphicsItem::isAdding() const
	{
		return m_bAdding;
	}

	bool ThreePointCircleGraphicsItem::isEditing() const
	{
		return SELECT_NONE != m_eSelType;
	}

	bool ThreePointCircleGraphicsItem::isVaild() const
	{
		QPointF center;
		double dRadius;
		return getCircle(m_vCirclePoint, center, dRadius);
	}

	BaseGraphicsItem::MouseDragType ThreePointCircleGraphicsItem::select(const QPointF & point, int * selType) const
	{
		MouseDragType eDragType = DRAG_NONE;
		SelectType eSelectType = SELECT_NONE;

		QPointF center;
		double dRadius;

		if (getCircle(m_vCirclePoint, center, dRadius))
		{
			QMap<SelectType, QRectF> dragRectMap;
			double dDistance = 5 / getViewScale();
			dragRectMap[SELECT_CENTER] = QRectF(center - QPointF(dDistance, dDistance), center + QPointF(dDistance, dDistance));
			dDistance = 3 / getViewScale();
			dragRectMap[SELECT_FIRST_POINT] = QRectF(m_vCirclePoint.at(0) - QPointF(dDistance, dDistance), m_vCirclePoint.at(0) + QPointF(dDistance, dDistance));
			dragRectMap[SELECT_SECOND_POINT] = QRectF(m_vCirclePoint.at(1) - QPointF(dDistance, dDistance), m_vCirclePoint.at(1) + QPointF(dDistance, dDistance));
			dragRectMap[SELECT_THIRD_POINT] = QRectF(m_vCirclePoint.at(2) - QPointF(dDistance, dDistance), m_vCirclePoint.at(2) + QPointF(dDistance, dDistance));

			for (auto iter = dragRectMap.begin(); iter != dragRectMap.end(); ++iter)
			{
				if (iter.value().contains(point))
				{
					eDragType = DRAG_EDIT;
					eSelectType = iter.key();
					break;
				}
			}

			if (SELECT_NONE == eSelectType)
			{
				// 将坐标移动到
				QPointF p = point - center;
				// 按照圆公式判断点是否在圆内
				double C = pow(p.x(), 2) / pow(dRadius, 2) + pow(p.y(), 2) / pow(dRadius, 2);
				// 判断鼠标在圆内部
				if (C <= 1.0)
				{
					eDragType = DRAG_MOVE;
					eSelectType = SELECT_ALL;
				}
			}
		}

		if (selType)
		{
			*selType = eSelectType;
		}
		return eDragType;
	}

	void ThreePointCircleGraphicsItem::cursor(const QPointF & point, QCursor & cursor) const
	{
		int nType;
		if (BaseGraphicsItem::DRAG_NONE != select(point, &nType))
		{
			switch (nType)
			{
			case SELECT_FIRST_POINT:
			case SELECT_SECOND_POINT:
			case SELECT_THIRD_POINT:
				cursor = Qt::PointingHandCursor;
				break;
			case SELECT_CENTER:
			case SELECT_ALL:
				cursor = Qt::SizeAllCursor;
				break;
			default:
				break;
			}
		}
	}

	void ThreePointCircleGraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent * event)
	{
		if (Qt::LeftButton == event->button())
		{
			m_pressMousePos = event->scenePos();

			if (isAdding())
			{
				if (SELECT_NONE == m_eSelType)
				{
					setCirclePoint(QVector<QPointF>(3, m_pressMousePos));
					m_eSelType = SELECT_SECOND_POINT;
					return;
				}
				else if (SELECT_SECOND_POINT == m_eSelType)
				{
					m_eSelType = SELECT_THIRD_POINT;
					m_vCirclePoint = { m_vCirclePoint.at(0), m_pressMousePos, m_pressMousePos };
					setCirclePoint(m_vCirclePoint);
					return;
				}
			}
			else
			{
				int nType;
				if (BaseGraphicsItem::DRAG_NONE != select(m_pressMousePos, &nType))
				{
					m_eSelType = static_cast<SelectType>(nType);
					return;
				}
			}
		}
		QFocusEvent focusEvent(QEvent::FocusOut, Qt::OtherFocusReason);
		focusOutEvent(&focusEvent);
	}

	void ThreePointCircleGraphicsItem::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
	{
		if (Qt::LeftButton == event->button())
		{
			if (isAdding() && (SELECT_SECOND_POINT == m_eSelType || SELECT_THIRD_POINT == m_eSelType))
				return;
		}
		QFocusEvent focusEvent(QEvent::FocusOut, Qt::OtherFocusReason);
		focusOutEvent(&focusEvent);
	}

	void ThreePointCircleGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent * event)
	{
		if (SELECT_NONE == m_eSelType)
			return;

		QPointF mousePos = event->scenePos();
		QRectF sceneRect = scene()->sceneRect();
		// 保证鼠标在场景内
		mousePos.setX(qMin(mousePos.rx(), sceneRect.right()));
		mousePos.setY(qMin(mousePos.ry(), sceneRect.bottom()));
		mousePos.setX(qMax(mousePos.rx(), sceneRect.left()));
		mousePos.setY(qMax(mousePos.ry(), sceneRect.top()));

		QVector<QPointF> vPoints = m_vCirclePoint;

		if (SELECT_FIRST_POINT == m_eSelType)
		{
			vPoints[0] = mousePos;
		}
		else if (SELECT_SECOND_POINT == m_eSelType)
		{
			vPoints[1] = mousePos;
		}
		else if (SELECT_THIRD_POINT == m_eSelType)
		{
			vPoints[2] = mousePos;
		}
		else if (SELECT_CENTER == m_eSelType || SELECT_ALL == m_eSelType)
		{
			QPolygonF polygon(vPoints);
			polygon.translate(mousePos - m_pressMousePos);
			vPoints = polygon;
			m_pressMousePos = mousePos;
		}

		QLineF line1(vPoints.at(0), vPoints.at(1));
		QLineF line2(vPoints.at(1), vPoints.at(2));

		if (!line1.isNull() && !line2.isNull())
		{
			double dAngle = line1.angleTo(line2);
			while (dAngle > 180)
			{
				dAngle -= 180;
			}
			while (dAngle < 0)
			{
				dAngle += 180;
			}

			if (qAbs(dAngle - 180) > 2 && dAngle > 2)
			{
				QPointF center;
				double dRadius;
				if (getCircle(vPoints, center, dRadius))
				{
					setCirclePoint(vPoints);
				}
			}
		}
	}

	void ThreePointCircleGraphicsItem::focusOutEvent(QFocusEvent * event)
	{
		Q_UNUSED(event);
		if (isAdding())
		{
			emit signalAddFinished();
			m_bAdding = false;
		}
		m_eSelType = SELECT_NONE;
	}

	QRectF ThreePointCircleGraphicsItem::boundingRect() const
	{
		QPainterPath path;;
		path.addPolygon(m_vCirclePoint);

		QPointF center;
		double dRadius;
		if (getCircle(m_vCirclePoint, center, dRadius))
		{
			path.addRect(QRectF(center - QPointF(dRadius, dRadius), center + QPointF(dRadius, dRadius)));
		}
		QRectF rectF = path.controlPointRect().adjusted(-5, -5, 5, 5);
		return rectF;
	}

	void ThreePointCircleGraphicsItem::paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget)
	{
		Q_UNUSED(option);
		Q_UNUSED(widget);

		if (this->scene())
		{
			painter->save();
			painter->setRenderHint(QPainter::Antialiasing);
			painter->setPen(getPen(getState()));

			// 通过反向缩放painter实现矢量绘制效果
			double dViewScale = getViewScale();
			painter->scale(1 / dViewScale, 1 / dViewScale);

			// painter缩小，则绘制坐标放大，保证显示位置不变
			QPointF firstPoint = m_vCirclePoint.at(0) * dViewScale;
			QPointF secondPoint = m_vCirclePoint.at(1) * dViewScale;
			QPointF thirdPoint = m_vCirclePoint.at(2) * dViewScale;

			QPointF center;
			double dRadius;
			QVector<QPointF> vPoints = { firstPoint, secondPoint, thirdPoint };
			if (getCircle(vPoints, center, dRadius))
			{
				// 绘制圆
				QRectF circleRect(center - QPointF(dRadius, dRadius), center + QPointF(dRadius, dRadius));
				painter->drawEllipse(circleRect);

				// 绘制中心十字
				double dDistance = 5;
				if (circleRect.width() >= 2 * dDistance && circleRect.height() >= 2 * dDistance)
				{
					painter->drawLine(circleRect.center() + QPointF(-dDistance, 0), circleRect.center() + QPointF(dDistance, 0));
					painter->drawLine(circleRect.center() + QPointF(0, -dDistance), circleRect.center() + QPointF(0, dDistance));
				}
			}

			// 叠加绘制选中状态 
			if (STATE_SELECT == getState())
			{
				QPointF radiusPoint(3, 3);
				painter->drawRect(QRectF(firstPoint - radiusPoint, firstPoint + radiusPoint));
				painter->drawRect(QRectF(secondPoint - radiusPoint, secondPoint + radiusPoint));
				painter->drawRect(QRectF(thirdPoint - radiusPoint, thirdPoint + radiusPoint));
			}
			painter->restore();
		}
	}

}
